package com.haoxuer.discover.trade.data.dao.impl;

import com.haoxuer.discover.rest.base.ResponseObject;
import com.haoxuer.discover.trade.data.dao.TradeAccountExceptionDao;
import com.haoxuer.discover.trade.data.dao.TradeInfoDao;
import com.haoxuer.discover.trade.data.dao.TradeStreamDao;
import com.haoxuer.discover.trade.data.entity.TradeAccountException;
import com.haoxuer.discover.trade.data.entity.TradeInfo;
import com.haoxuer.discover.trade.data.entity.TradeStream;
import com.haoxuer.discover.trade.data.enums.AccountType;
import com.haoxuer.discover.trade.data.request.TradeRequest;
import com.haoxuer.discover.user.utils.SecurityUtil;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.haoxuer.discover.data.core.CriteriaDaoImpl;
import com.haoxuer.discover.trade.data.dao.TradeAccountDao;
import com.haoxuer.discover.trade.data.entity.TradeAccount;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Date;

/**
 * Created by imake on 2018年12月10日09:54:27.
 */
@Repository
public class TradeAccountDaoImpl extends CriteriaDaoImpl<TradeAccount, Long> implements TradeAccountDao {


    @Autowired
    TradeStreamDao streamDao;

    @Autowired
    TradeInfoDao infoDao;

    @Autowired
    TradeAccountExceptionDao exceptionDao;

    @Override
    public TradeAccount findById(Long id) {
        if (id == null) {
            return null;
        }
        return get(id);
    }

    @Override
    public TradeAccount save(TradeAccount bean) {

        getSession().save(bean);


        return bean;
    }

    @Override
    public TradeAccount deleteById(Long id) {
        TradeAccount entity = super.get(id);
        if (entity != null) {
            getSession().delete(entity);
        }
        return entity;
    }

    @Override
    public TradeAccount initNormal() {
        return init(AccountType.normal);
    }

    @Override
    public TradeAccount initSpecial() {
        return init(AccountType.special);
    }

    private TradeAccount init(AccountType accountType) {
        TradeAccount bean = new TradeAccount();
        bean.setAmount(new BigDecimal(0));
        bean.setAccountType(accountType);
        sign(bean);
        getSession().save(bean);
        return bean;
    }

    @Override
    public ResponseObject trade(TradeRequest request) {
        ResponseObject result = new ResponseObject();
        if (request.getAmount() == null || request.getAmount().floatValue() <= 0) {
            result.setMsg("金额不能为负数");
            result.setCode(-303);
            return result;
        }
        TradeAccount fromAccount = findById(request.getFrom());
        if (fromAccount.getAccountType() == AccountType.normal) {
            if (fromAccount.getAmount().compareTo(request.getAmount()) < 0) {
                result.setMsg("余额不足");
                result.setCode(-301);
                return result;
            }
        }
        String sign = signString(fromAccount);
        if (!sign.equals(fromAccount.getCheckValue())) {
            BigDecimal money = streamDao.lastMoney(fromAccount.getId());
           if (fromAccount.getAmount().equals(money)){

           }else {
             result.setMsg("账号异常");
             result.setCode(-302);
             TradeAccountException exception = new TradeAccountException();
             exception.setAccount(fromAccount);
             exception.setOldSalt(fromAccount.getSalt());
             exception.setOldCheckValue(fromAccount.getCheckValue());
             exception.setOldAmount(fromAccount.getAmount());
             exception.setCheckValue(sign);
             exception.setAmount(money);
             exceptionDao.save(exception);
             return result;
           }
        }

        TradeAccount toAccount = findById(request.getTo());
        String tosign = signString(toAccount);
        if (!tosign.equals(toAccount.getCheckValue())) {
          BigDecimal money = streamDao.lastMoney(toAccount.getId());
          if (toAccount.getAmount().equals(money)){

          }else{
            result.setMsg("账号异常");
            result.setCode(-302);

            TradeAccountException exception = new TradeAccountException();
            exception.setAccount(toAccount);
            exception.setOldSalt(toAccount.getSalt());
            exception.setOldCheckValue(toAccount.getCheckValue());
            exception.setOldAmount(toAccount.getAmount());
            exception.setCheckValue(tosign);
            exception.setAmount(money);
            exceptionDao.save(exception);
            return result;
          }

        }

        TradeInfo trade = new TradeInfo();
        trade.setAmount(request.getAmount());
        trade.setTo(toAccount);
        trade.setFrom(fromAccount);
        infoDao.save(trade);

        handFrom(request, fromAccount, trade);
        handTo(request, toAccount, trade);

        return result;
    }

    private void handTo(TradeRequest request, TradeAccount toAccount, TradeInfo trade) {
        BigDecimal money = request.getAmount();
        BigDecimal before = toAccount.getAmount();
        BigDecimal after = toAccount.getAmount().add(money);

        toAccount.setAmount(after);
        toAccount.setLastDate(new Date());
        sign(toAccount);

        TradeStream stream = new TradeStream();
        stream.setAmount(money);
        stream.setAccount(toAccount);
        stream.setNote(request.getNote());
        stream.setPreAmount(before);
        stream.setAfterAmount(after);
        stream.setChangeType(request.getChangeType().getType());
        stream.setInfo(trade);
        streamDao.save(stream);
    }

    private void handFrom(TradeRequest request, TradeAccount fromAccount, TradeInfo trade) {
        BigDecimal money = request.getAmount();
        BigDecimal before = fromAccount.getAmount();
        BigDecimal after = fromAccount.getAmount().subtract(money);

        fromAccount.setAmount(after);
        fromAccount.setLastDate(new Date());
        sign(fromAccount);

        TradeStream stream = new TradeStream();
        stream.setAmount(money.multiply(new BigDecimal(-1)));
        stream.setAccount(fromAccount);
        stream.setNote(request.getNote());
        stream.setPreAmount(before);
        stream.setAfterAmount(after);
        stream.setChangeType(request.getChangeType().getType());
        stream.setInfo(trade);
        streamDao.save(stream);
    }

    DecimalFormat df1 = new DecimalFormat("0.00");

    private void sign(TradeAccount bean) {
        SecurityUtil securityUtil = new SecurityUtil();
        bean.setSalt(securityUtil.getSalt());
        StringBuffer buffer = new StringBuffer();
        buffer.append("account-");
        buffer.append(df1.format(bean.getAmount()));
        buffer.append(bean.getSalt());

        String check = securityUtil.entryptPassword(buffer.toString());
        bean.setCheckValue(check);
    }

    private String signString(TradeAccount bean) {
        SecurityUtil securityUtil = new SecurityUtil(bean.getSalt());
        StringBuffer buffer = new StringBuffer();
        buffer.append("account-");
        buffer.append(df1.format(bean.getAmount()));
        buffer.append(bean.getSalt());
        String check = securityUtil.entryptPassword(buffer.toString());
        return check;
    }

    @Override
    protected Class<TradeAccount> getEntityClass() {
        return TradeAccount.class;
    }

    @Autowired
    public void setSuperSessionFactory(SessionFactory sessionFactory) {
        super.setSessionFactory(sessionFactory);
    }
}